package com.meme.util;

import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import  org.w3c.dom.bootstrap.DOMImplementationRegistry;
import  org.w3c.dom.ls.DOMImplementationLS;
import  org.w3c.dom.ls.LSParser;
import  org.w3c.dom.ls.LSSerializer;
import  org.w3c.dom.ls.LSOutput;
import  org.w3c.dom.DOMConfiguration;

import java.io.File;

import java.io.StringWriter;

import org.apache.log4j.Logger;


public class XmlUtil 
{
	static Logger logger = Logger.getLogger (XmlUtil.class);
	
	public static Document loadXmlFile (String xmlFilename)
	{
		// return parseXmlFile_JAXP (xmlFilename);
		return parseXmlFile_DOMLevel3 (xmlFilename);
	}
	
	public static Document createNewDocument ()
	{
		try 
		{
	        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	        factory.setNamespaceAware(false);
	        DocumentBuilder builder = factory.newDocumentBuilder();
	        Document document = builder.newDocument();
	 		return document;
		}
		catch (FactoryConfigurationError e) 
		{	
			logger.fatal("unable to get a document builder factory: " + e.toString() );
		} 
		catch (ParserConfigurationException e) 
		{
			logger.fatal("parser was unable to be configured: " + e.toString() );
		}
		catch (Exception e)
		{
			logger.fatal( "Unknown error in parseXmlFile_JAXP." );
		}
		
		return null;
	}
	
	public static void writeXmlFile (Document document, String xmlFilename)
	{
		try
		{
			DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
	
			DOMImplementationLS impl = (DOMImplementationLS)registry.getDOMImplementation("LS");
	
			LSSerializer writer = impl.createLSSerializer();
			
			DOMConfiguration domConfig = writer.getDomConfig();
			domConfig.setParameter("format-pretty-print", Boolean.TRUE);

			writer.writeToURI(document, xmlFilename);                     
		}
		catch (ClassNotFoundException e)
		{
			logger.fatal( e.toString() );
		}
		catch (IllegalAccessException e)
		{
			logger.fatal( e.toString() );
		}
		catch (InstantiationException e)
		{
			logger.fatal( e.toString() );
		}
		catch (Exception e)
		{
			logger.fatal( "Unknown error in writeXmlFile" );
		}
	}
	
	public static Document parseXmlFile_JAXP (String xmlFilename)
	{
		try 
		{
		    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		    factory.setNamespaceAware(false);
		    DocumentBuilder builder = factory.newDocumentBuilder();
		    Document document = builder.parse(xmlFilename);
			return document;
		}
		catch (FactoryConfigurationError e) 
		{	
			logger.fatal("unable to get a document builder factory: " + e.toString() );
		} 
		catch (ParserConfigurationException e) 
		{
			logger.fatal("parser was unable to be configured: " + e.toString() );
		}
		catch (SAXException e) 
		{
			logger.fatal("parsing error: " + e.toString() );
		} 
		catch (IOException e) 
		{
			logger.fatal("i/o error: " + e.toString() );
		}
		catch (Exception e)
		{
			logger.fatal( "Unknown error in parseXmlFile_JAXP." );
		}
		
		return null;
	}
	
	public static Document parseXmlFile_DOMLevel3 (String xmlFilename)
	{
		try
		{
			DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
	
			DOMImplementationLS impl = (DOMImplementationLS)registry.getDOMImplementation("LS");
	
			LSParser builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
				
			Document document = builder.parseURI(xmlFilename);
			
			return document;
		} 
		catch (ClassNotFoundException e)
		{
			logger.fatal( e.toString() );
		}
		catch (IllegalAccessException e)
		{
			logger.fatal( e.toString() );
		}
		catch (InstantiationException e)
		{
			logger.fatal( e.toString() );
		}
		catch (Exception e)
		{
			logger.fatal( "Unknown error in parseXmlFile_DOMLevel3." );
		}
		
		return null;
	}
	
	


	public static Element getChildElementByName (Node parent, String name)
	{
		Node node = parent.getFirstChild();
		while (node != null)
		{
			if (node instanceof Element )
			{
				Element element = (Element) node;
				if (element.getTagName().equals(name))
					return element;
			}
			
			node = node.getNextSibling();
		}
		
		return null;
	}

	public static Element[] getChildElementsByName (Node parent, String name)
	{
		int count = 0;

		Node node = parent.getFirstChild();
		while (node != null)
		{
			if (node instanceof Element )
			{
				Element element = (Element) node;
				if (element.getTagName().equals(name))
					++ count;
			}
			
			node = node.getNextSibling();
		}
		
		Element[] elements = new Element[count];
		int index = 0;
		node = parent.getFirstChild();
		while (node != null)
		{
			if (node instanceof Element )
			{
				Element element = (Element) node;
				if (element.getTagName().equals(name))
					elements [index ++] = element;
			}
			
			node = node.getNextSibling();
		}

		
		return elements;
	}
	
	public static int parseAttributeAsInt (Element element, String attrName)
	{
		try
		{
			return Integer.parseInt(element.getAttribute (attrName) );
		}
		catch (Exception e)
		{
			logger.error(e);
			logger.error ("Error in parseAttributeAsInt: element=" + element.getTagName() + " , attribute=" + attrName);
			
			return 0;
		}
	}
	
	public static float parseAttributeAsFloat (Element element, String attrName)
	{
		try
		{
			return Float.parseFloat(element.getAttribute (attrName) );
		}
		catch (Exception e)
		{
			logger.error(e);
			logger.error ("Error in parseAttributeAsFloat: element=" + element.getTagName() + " , attribute=" + attrName);
			
			return 0;
		}
	}
	
	public static boolean parseAttributeAsBoolean (Element element, String attrName)
	{
		try
		{
			return Boolean.parseBoolean(element.getAttribute (attrName) );
		}
		catch (Exception e)
		{
			logger.error(e);
			logger.error ("Error in parseAttributeAsBoolean: element=" + element.getTagName() + " , attribute=" + attrName);
			
			return false;
		}
	}
	
	public static void addProperty (Element element, Element property)
	{
	}
	
	public static void addChild (Element parent, Element child)
	{
		
	}
}



